/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.hadss.avoidarea.utils;

import static org.hadss.avoidarea.constant.AvoidAreaType.TYPE_CUTOUT;
import static org.hadss.avoidarea.constant.AvoidAreaType.TYPE_NAVIGATION_INDICATOR;
import static org.hadss.avoidarea.constant.AvoidAreaType.TYPE_SYSTEM;
import static org.hadss.avoidarea.constant.AvoidAreaType.TYPE_SYSTEM_GESTURE;

import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;

import java.util.Iterator;
import java.util.Map;

import javax.annotation.Nonnull;

/**
 * 窗口规避区域工具类：提供获取规避区域的方法
 *
 * @since 2025/5/12
 */
public class AvoidAreaUtils {

    private static final String TAG = AvoidAreaUtils.class.getSimpleName();
    private static final String VISIBLE = "visible";
    private static final String TOP_RECT = "topRect";
    private static final String LEFT_RECT = "leftRect";
    private static final String RIGHT_RECT = "rightRect";
    private static final String BOTTOM_RECT = "bottomRect";
    private static final String RECT_LEFT = "left";
    private static final String RECT_TOP = "top";
    private static final String RECT_WIDTH = "width";
    private static final String RECT_HEIGHT = "height";

    /**
     * 根据提供的RN数据结构返回对应的JSON字符串
     *
     * @param map 提供给RN数据结构
     * @return JSON字符串
     */
    public static String getWritableMapJson(WritableMap map) {
        if (map == null) {
            return "{}";
        }
        Iterator<Map.Entry<String, Object>> entryIterator = map.getEntryIterator();
        StringBuilder stringBuilder = new StringBuilder("{");
        while (entryIterator.hasNext()) {
            Map.Entry<String, Object> next = entryIterator.next();
            stringBuilder.append("\"").append(next.getKey()).append("\"").append(":");
            stringBuilder.append(next.getValue());
            if (entryIterator.hasNext()) {
                stringBuilder.append(",");
            }
        }
        stringBuilder.append("}");
        return stringBuilder.toString();
    }

    /**
     * 根据RN下发的避让区域类型转换为String格式
     *
     * @param type 避让区域类型
     * @return 避让区域类型的String格式
     */
    public static String typeToStringName(double type) {
        if (TYPE_SYSTEM == type) {
            return "TYPE_SYSTEM";
        } else if (TYPE_CUTOUT == type) {
            return "TYPE_CUTOUT";
        } else if (TYPE_NAVIGATION_INDICATOR == type) {
            return "TYPE_NAVIGATION_INDICATOR";
        } else if (TYPE_SYSTEM_GESTURE == type) {
            return "TYPE_SYSTEM_GESTURE";
        } else {
            return "TYPE_KEYBOARD";
        }
    }

    /**
     * 获取RN方法默认返回值
     *
     * @return WritableMap
     */
    public static WritableMap getDefaultWritableMap() {
        WritableMap map = Arguments.createMap();
        map.putBoolean(VISIBLE, false);
        map.putMap(LEFT_RECT, getRectToWritableMap(0, 0));
        map.putMap(TOP_RECT, getRectToWritableMap(0, 0));
        map.putMap(RIGHT_RECT, getRectToWritableMap(0, 0));
        map.putMap(BOTTOM_RECT, getRectToWritableMap(0, 0));
        return map;
    }

    /**
     * 获取导航栏避让区域
     *
     * @param writableMap writableMap
     * @param activity    应用上下文
     */
    public static void getAvoidAreaNavigation(WritableMap writableMap, Activity activity) {
        if (activity == null) {
            Log.w(TAG, "getAvoidAreaNavigation activity == null");
            return;
        }
        writableMap.putBoolean(VISIBLE, AvoidAreaUtils.isNavigationBarVisible(activity));
        int navigationBarHeight = AvoidAreaUtils.getNavigationBarHeight(activity);
        WritableMap rectToWritableMap =
            getRectToWritableMap(0, navigationBarHeight, 0,
                AvoidAreaUtils.getScreenHeight(activity) - navigationBarHeight);
        writableMap.putMap(BOTTOM_RECT, rectToWritableMap);
    }


    /**
     * 获取刘海屏避让区域
     *
     * @param writableMap writableMap
     * @param activity    应用上下文
     */
    public static void getAvoidAreaCutout(WritableMap writableMap, Activity activity) {
        if (activity == null) {
            Log.w(TAG, "getAvoidAreaCutout activity == null");
            return;
        }
        // 刘海屏避让区域
        writableMap.putBoolean(VISIBLE, false);

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
            WindowInsets rootWindowInsets = activity.getWindow().getDecorView().getRootWindowInsets();
            if (rootWindowInsets.getDisplayCutout() == null) {
                return;
            }
            setRectForMap(rootWindowInsets.getDisplayCutout().getBoundingRectTop(), writableMap, TOP_RECT);
            setRectForMap(rootWindowInsets.getDisplayCutout().getBoundingRectBottom(), writableMap, BOTTOM_RECT);
            setRectForMap(rootWindowInsets.getDisplayCutout().getBoundingRectLeft(), writableMap, LEFT_RECT);
            setRectForMap(rootWindowInsets.getDisplayCutout().getBoundingRectRight(), writableMap, RIGHT_RECT);
        }

    }

    /**
     * 将设备边距信息输入至map中
     *
     * @param rect        设备边距信息
     * @param writableMap writableMap
     * @param rectName    边距信息
     */
    private static void setRectForMap(Rect rect, WritableMap writableMap, String rectName) {
        WritableMap rectToWritableMap =
            getRectToWritableMap(rect.width(), rect.height(), rect.left, rect.top);
        writableMap.putMap(rectName, rectToWritableMap);
    }

    /**
     * 创建RN Rect结构数据
     *
     * @param width  宽度
     * @param height 高度
     * @return RN Rect的数据
     */
    private static WritableMap getRectToWritableMap(int width, int height) {
        return getRectToWritableMap(width, height, 0, 0);
    }

    /**
     * 创建RN Rect结构数据
     *
     * @param width  宽度
     * @param height 高度
     * @param left   left
     * @param top    top
     * @return RN Rect的数据
     */
    private static WritableMap getRectToWritableMap(int width, int height, int left, int top) {
        WritableNativeMap writableNativeMap = new WritableNativeMap();
        writableNativeMap.putInt(RECT_LEFT, left);
        writableNativeMap.putInt(RECT_TOP, top);
        writableNativeMap.putInt(RECT_WIDTH, width);
        writableNativeMap.putInt(RECT_HEIGHT, height);
        return writableNativeMap;
    }

    /**
     * 获取状态栏避让区域
     *
     * @param writableMap writableMap
     * @param context     应用上下文
     */
    public static void getAvoidAreaSystem(WritableMap writableMap, Context context) {
        if (context == null) {
            Log.w(TAG, "getAvoidAreaSystem context == null");
            return;
        }
        writableMap.putBoolean(VISIBLE, true);
        WritableMap rectToWritableMap =
            getRectToWritableMap(AvoidAreaUtils.getScreenWidth(context),
                AvoidAreaUtils.getStatusBarHeight(context));
        writableMap.putMap(TOP_RECT, rectToWritableMap);
    }

    /**
     * 获取屏幕宽度
     *
     * @param context 应用上下文
     * @return 屏幕宽度
     */
    private static int getScreenWidth(@Nonnull Context context) {
        WindowManager windowManager =
            (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Point point = new Point();
        windowManager.getDefaultDisplay().getRealSize(point);
        return point.x;
    }


    /**
     * 获取屏幕高度
     *
     * @param context 应用上下文
     * @return 屏幕高度
     */
    private static int getScreenHeight(@Nonnull Context context) {
        WindowManager windowManager =
            (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Point point = new Point();
        windowManager.getDefaultDisplay().getRealSize(point);
        return point.y;
    }

    /**
     * 获取顶部导航栏高度
     *
     * @param context 应用上下文
     * @return 顶部导航栏高度
     */
    public static int getStatusBarHeight(@Nonnull Context context) {
        int statusBarHeight = 0;
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
        }
        return statusBarHeight;
    }

    /**
     * 获取底部导航栏高度
     *
     * @param activity 应用上下文
     * @return 底部导航栏高度
     */
    public static int getNavigationBarHeight(@Nonnull Activity activity) {
        int statusBarHeight = 0;
        int resourceId = activity.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceId > 0) {
            statusBarHeight = activity.getResources().getDimensionPixelSize(resourceId);
        }
        return statusBarHeight;
    }

    /**
     * 获取导航栏是否可见
     *
     * @param activity 应用上下文
     * @return 导航栏是否可见
     */
    private static boolean isNavigationBarVisible(@Nonnull Activity activity) {
        int uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility();
        boolean isFullScreen = (uiOptions & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
        boolean isImmersiveMode = (uiOptions & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
        return !isFullScreen && !isImmersiveMode && isNavigationBarPresent(activity);
    }

    /**
     * 获取导航栏是否存在
     *
     * @param activity 应用上下文
     * @return 导航栏是否存在
     */
    private static boolean isNavigationBarPresent(@Nonnull Activity activity) {
        Rect rect = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        int screenHeight = getScreenHeight(activity);
        int usableHeight = rect.height();
        return screenHeight > usableHeight;
    }
}
